package com.gitee.mazhenggg.demo.auth.service;

import com.gitee.mazhenggg.demo.auth.security.SecurityUserDetails;
import com.gitee.mazhenggg.demo.common.constant.TokenConstants;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtException;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.io.Decoders;
import io.jsonwebtoken.security.Keys;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.User;
import org.springframework.stereotype.Component;
import sun.misc.BASE64Decoder;

import java.io.IOException;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.X509EncodedKeySpec;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;

/**
 * @author mazhenggg
 */
@Slf4j
@Component
public class JwtService {


    public String generateToken(SecurityUserDetails securityUserDetails) throws NoSuchAlgorithmException, IOException, InvalidKeySpecException {
        Map<String, Object> userInfo = new HashMap<>();
        userInfo.put("userId", securityUserDetails.getId());
        userInfo.put("userName", securityUserDetails.getUsername());
//        userInfo.put("name", securityUserDetails.getName());
//        userInfo.put("avatar", securityUserDetails.getAvatar());
//        userInfo.put("userType", securityUserDetails.getUserType());
//        userInfo.put("schoolId", securityUserDetails.getSchoolId());
//        userInfo.put("schoolName", securityUserDetails.getSchoolName());
//        userInfo.put("roles", securityUserDetails.getRoles());
//        userInfo.put("currentRole", securityUserDetails.getCurrentRole());
       return createToken(userInfo, securityUserDetails.getUsername());
    }

    private String createToken(Map<String, Object> userInfo, String subject) throws NoSuchAlgorithmException, InvalidKeySpecException, IOException {
        byte[] secretKeyBytes = Decoders.BASE64.decode(TokenConstants.secretKey);
        long currentTimeMillis = System.currentTimeMillis();
        String jws = Jwts.builder()
                .setSubject(subject)
                .setIssuedAt(new Date(currentTimeMillis))
                .setIssuer(TokenConstants.issuer)
                .setExpiration(new Date(currentTimeMillis + TokenConstants.expireTime))
                .claim("userInfo", userInfo)
                // 加密算法 RS256 不对称 HS256 对称
                //.signWith(privateKey, SignatureAlgorithm.RS256)
                .signWith(Keys.hmacShaKeyFor(secretKeyBytes), SignatureAlgorithm.HS256)
                .compact();

        //        byte[] keyBytes = (new BASE64Decoder()).decodeBuffer(rsaPrivateKey);
//         不加上这行java.security.Security.addProvider ,就会报java.security.InvalidKeyException: IOException : Short read of DER length 错误
//        java.security.Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
//        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
//        KeyFactory keyFactory =  KeyFactory.getInstance("RSA");
//        PrivateKey privateKey = keyFactory.generatePrivate(keySpec);
        return jws;
    }




    public String createToken(Authentication authentication) {
        return createToken(authentication.getName());
    }

    public String createToken(String userName) {

        long now = System.currentTimeMillis();

        Date validity;
        validity = new Date(now + 18000 * 1000L);

        Claims claims = Jwts.claims().setSubject(userName);
        return Jwts.builder().setClaims(claims).setExpiration(validity)
                .signWith(Keys.hmacShaKeyFor(getSecretKeyBytes()), SignatureAlgorithm.HS256).compact();
    }


    public Map<String, Object> getUserInfoMap(String token) throws JwtException{
        Claims claims = null;
        try {
            claims = Jwts.parserBuilder().setSigningKey(getSecretKeyBytes()).build()
                    .parseClaimsJws(token).getBody();
        } catch (JwtException e) {
            // 不受信任的JWT
            log.error("当前jwtToken不受信任，或被串改：{}", token);
            throw new JwtException("当前jwtToken不受信任，或被串改");
        }

        Map<String, Object> userInfoMap = claims.get("userInfo", Map.class);
        return userInfoMap;
    }

    public void validateToken(String token) {
        Jwts.parserBuilder().setSigningKey(getSecretKeyBytes()).build().parseClaimsJws(token);
    }

    public byte[] getSecretKeyBytes() {
        byte[] secretKeyBytes = Decoders.BASE64.decode(TokenConstants.secretKey);
        return secretKeyBytes;
    }



}
